<?php
/**
 * BoxBilling
 *
 * @copyright BoxBilling, Inc (http://www.boxbilling.com)
 * @license   Apache-2.0
 *
 * Copyright BoxBilling, Inc
 * This source file is subject to the Apache-2.0 License that is bundled
 * with this source code in the file LICENSE
 */


namespace Box\Mod\Formbuilder;
use Box\InjectionAwareInterface;

class Service implements InjectionAwareInterface
{
    /**
     * @var \Box_Di
     */
    protected $di = null;

    /**
     * @param \Box_Di $di
     */
    public function setDi($di)
    {
        $this->di = $di;
    }

    /**
     * @return \Box_Di
     */
    public function getDi()
    {
        return $this->di;
    }


    public function getFormFieldsTypes()
    {
        return array(
            "text" => 'Text input',
            "select" => 'Dropdown',
            "radio" => 'Radio select',
            "checkbox" => 'Checkbox',
            "textarea" => 'Text area'
        );
    }

    public function typeValidation($type)
    {
        return array_key_exists($type, $this->getFormFieldsTypes());
    }

    public function isArrayUnique($data)
    {
        $unique = array_unique($data);
        return (count($data) === count($unique));

    }

    public function addNewForm($data)
    {
        $data["style"]["type"] = isset ($data["type"])? $data["type"] : "horizontal";
        $data["style"]["show_title"] = isset ($data["show_title"])? $data["show_title"] : "0";
        $data["style"] = json_encode($data["style"],JSON_FORCE_OBJECT);

        $bean = $this->di['db']->dispense('Form');
        $bean->name = $data['name'];
        $bean->style =  $data['style'];
        $bean->created_at = date('c');
        $bean->updated_at = date('c');

        $form_id = $this->di['db']->store($bean);
        $this->di['logger']->info('Created new form %s with id %s', $data['name'], $form_id);
        return $form_id;
    }

    public function addNewField($field) //TODO server-side required check
    {
        $field_number = (int)$this->getFormFieldsCount($field['form_id']) + 1;

        $formId = $field['form_id'];
        $types = $this->getFormFieldsTypes();
        $type = $field["type"];
        $label = isset($field['label']) ? $field['label'] : $types[$type] . " " . $field_number;
        $name = isset($field['name']) ? $field['name'] : ($this->slugify("new_" . $type) . "_" . $field_number);


        if ($type == "select" || $type == "checkbox" || $type == "radio") {
            $field['options'] = '{"First option":"1", "Second option": "2", "Third option":"3"}';
        }
        if ($field['type'] == "textarea" && !isset($field['options'])) {
            $field['options'] = '{"height":"100", "width": "300"}';
        }
        if (isset($field['default_value'])) {
            $field['default_value'] = is_array($field['default_value']) ? json_encode($field['default_value'], JSON_FORCE_OBJECT) : $field['default_value'];
        }
        if (isset ($field['options']) && is_array($field['options'])) {
            $field['options'] = json_encode($field['options'], JSON_FORCE_OBJECT);
        }
        $bean = $this->di['db']->dispense('FormField');
        $bean->form_id = $formId;
        $bean->name = $name;
        $bean->label = $label;
        $bean->hide_label = isset($field['hide_label']) ? $field['hide_label'] : null;
        $bean->description = isset($field['description']) ? $field['description'] : null;
        $bean->type = $field['type'];
        $bean->default_value = isset($field['default_value']) ? $field['default_value'] : null;
        $bean->required = isset($field['required']) ? $field['required'] : null;
        $bean->hidden = isset($field['hidden']) ? $field['hidden'] : null;
        $bean->readonly = isset($field['readonly']) ? $field['readonly'] : null;
        $bean->options = isset($field['options']) ? $field['options'] : null;
        $bean->prefix = isset($field['prefix']) ? $field['prefix'] : null;
        $bean->suffix = isset($field['suffix']) ? $field['suffix'] : null;
        $bean->show_initial = isset($field['show_initial']) ? $field['show_initial'] : null;
        $bean->show_middle = isset($field['show_middle']) ? $field['show_middle'] : null;
        $bean->show_prefix = isset($field['show_prefix']) ? $field['show_prefix'] : null;
        $bean->show_suffix = isset ($field['show_suffix']) ? $field['show_suffix'] : null;
        $bean->text_size = isset($field['text_size']) ? $field['text_size'] : null;
        $bean->created_at = date('c');
        $bean->updated_at = date('c');

        $fieldId = $this->di['db']->store($bean);
        $this->di['logger']->info('Added new field %s to form %s', $fieldId, $field['form_id']);

        return $fieldId;
    }


    private function slugify($text)
    {

        // replace non letter or digits by _
        $text = preg_replace('~[^\\pL\d]+~u', '_', $text);

        // trim
        $text = trim($text, '_');

        // transliterate
        $text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);

        // lowercase
        $text = strtolower($text);

        // remove unwanted characters
        $text = preg_replace('~[^-\w]+~', '', $text);

        if (is_numeric(substr($text, 0, 1))) {
            throw new \Box_Exception ('Field name can not start with number.', null, 1649);
        }

        if (empty($text)) {
            throw new \Box_Exception ('Field name can not be empty. Please make sure it is not empty and does not contain special characters.', null, 3502);
        }

        return $text;
    }


    public function updateField($field)
    {
        $fieldId = $field['id'];

        $label = isset($field['label']) ? $field['label'] : 'New field';
        $name = $this->slugify($field['name']);

        $get_field = $this->getField($field['id']);
        $field['form_id'] = $get_field['form_id'];

        if ($this->formFieldNameExists(array("form_id" => $field["form_id"], "field_name" => $field["name"], "field_id" => $fieldId))) {
            throw new \Box_Exception ('Unfortunately field with this name exists in this form already. Form must have different field names.', null, 7628);
        }

        $field['options'] = isset($field['options']) ? json_encode($field['options']) : "";
        if (isset($field['default_value'])) {
            $field['default_value'] = is_array($field['default_value']) ? json_encode($field['default_value'], JSON_FORCE_OBJECT) : $field['default_value'];
        }

        if (isset($field['type'])) {
            if ($field['type'] == "checkbox" || $field['type'] == "radio" || $field['type'] == "select") {
                if (!$this->isArrayUnique(array_filter($field['values'], 'strlen'))) {
                    throw new \Box_Exception(ucfirst($field['type']) . ' values must be unique', null, 1597);
                }
                if (!$this->isArrayUnique(array_filter($field['labels'], 'strlen'))) {
                    throw new \Box_Exception(ucfirst($field['type']) . ' labels must be unique', null, 1598);
                }
                $field['options'] = array_combine($field['labels'], $field['values']);
                $field['options'] = array_filter($field['options'], 'strlen');
                $field['options'] = json_encode($field['options'], JSON_FORCE_OBJECT);
            }
            if ($field['type'] == "textarea") {
                if (count($field['textarea_size']) != count(array_filter($field['textarea_size'], 'is_numeric'))) {
                    throw new \Box_Exception('Textarea size options must be integer values', null, 3510);
                }
                $field['options'] = array_combine($field['textarea_option'], $field['textarea_size']);
                $field['options'] = json_encode($field['options'], JSON_FORCE_OBJECT);
            }
        }

        $bean = $this->di['db']->dispense('FormField');
        $bean->id = $fieldId;
        $bean->name = $name;
        $bean->label = $label;
        $bean->hide_label = isset($field['hide_label']) ? $field['hide_label'] : null;
        $bean->description = isset($field['description']) ? $field['description'] : null;
        $bean->default_value = isset($field['default_value']) ? $field['default_value'] : null;
        $bean->required = isset($field['required']) ? $field['required'] : null;
        $bean->hidden = isset($field['hidden']) ? $field['hidden'] : null;
        $bean->readonly = isset($field['readonly']) ? $field['readonly'] : null;
        $bean->options = $field['options'];
        $bean->prefix = isset($field['prefix']) ? $field['prefix'] : null;
        $bean->suffix = isset ($field['suffix']) ? $field['suffix'] : null;
        $bean->show_initial = isset($field['show_initial']) ? $field['show_initial'] : null;
        $bean->show_middle = isset($field['show_middle']) ? $field['show_middle'] : null;
        $bean->show_prefix = isset($field['show_prefix']) ? $field['show_prefix'] : null;
        $bean->show_suffix = isset($field['show_suffix']) ? $field['show_suffix'] : null;
        $bean->text_size = isset($field['text_size']) ? $field['text_size'] : null;
        $bean->updated_at = date('c');

        $this->di['db']->store($bean);
        $this->di['logger']->info('Updated custom form %s', $fieldId);
        return $fieldId;
    }

    public function getForm($formId)
    {
        $formModel = $this->di['db']->load('Form', $formId);
        if (!$formModel instanceof \Model_Form) {
            throw new \Box_Exception('Form not found', null, 9632);
        }
        $result = $this->di['db']->toArray($formModel);

        $result['style'] = json_decode($result['style'], true);
        $result['fields'] = $this->getFormFields($result['id']);
        $result['fields'] = $this->fieldsJsonDecode($result['fields']);
        return $result;
    }

    public function getFormFields($formId)
    {
        $sql = ("
        SELECT *
        FROM form_field
        WHERE form_id = :form_id
        ORDER BY ID asc
        ");
        $result = $this->di['db']->getAll($sql, array(':form_id' => $formId));
        return $result;

    }

    private function fieldsJsonDecode($fields)
    {
        foreach ($fields as $key => $r) {
            $fields[$key]['options'] = json_decode($r['options'], true);
            $fields[$key]['default_value'] = (json_decode($r['default_value'])) ? (json_decode($r['default_value'], true)) : $r['default_value'];
        }
        return $fields;
    }

    public function getFormFieldsCount($form_id)
    {
        $sql = ("
        SELECT COUNT(*)
        FROM form_field
        WHERE form_id = :form_id
        ");

        return $this->di['db']->getCell($sql, array(':form_id' => $form_id));
    }


    public function getFormPairs()
    {
        $sql = "
            SELECT id, name
            FROM form
        ";

        return $this->di['db']->getAssoc($sql);
    }

    public function getField($fieldId)
    {
        $field = $this->di['db']->load('FormField', $fieldId);
        if (!$field instanceof \Model_FormField){
            throw new \Box_Exception ("Field was not found", null, 2575);
        }
        $result = $this->di['db']->toArray($field);
        if (!isset($result['id'])) {
            throw new \Box_Exception ("Field was not found", null, 2575);
        }
        if (substr($result["options"], 0, 1) == "{" || substr($result["options"], 0, 1) == "[") {
            $result['options'] = json_decode($result['options']);
        }
        return $result;

    }

    public function removeForm($form_id)
    {
        $sql = "DELETE
            FROM form_field
            WHERE  form_id = ?
        ";
        $this->di['db']->exec($sql, array($form_id));

        $sql2 = "DELETE
        FROM form
        WHERE id = ?";
        $this->di['db']->exec($sql2, array($form_id));

        $sql3 = "UPDATE product
        SET form_id = NULL
        WHERE form_id = ?
        ";
        $this->di['db']->exec($sql3, array($form_id));

        $sql4 = "UPDATE client_order
        SET form_id = NULL
        WHERE form_id = :form_id
        ";
        $this->di['db']->exec($sql4, array(':form_id' => $form_id));

        $this->di['logger']->info('Deleted custom form %s', $form_id);
        return true;
    }

    public function removeField($data)
    {
        $fieldModel = $this->di['db']->load('FormField', $data['id']);
        if (!$fieldModel instanceof \Model_FormField){
            throw new \Box_Exception ("Field was not found", null, 1641);
        }

        $this->di['db']->trash($fieldModel);
        $this->di['logger']->info('Deleted custom field %s', $data['id']);
        return true;
    }


    public function formFieldNameExists($data)
    {
        $form_id = $data['form_id'];
        $field_name = $data['field_name'];
        $field_id = $data['field_id'];
        $sql = ("
        SELECT COUNT( * )
        FROM  `form_field`
        WHERE form_id = :form_id
        AND name =  :field_name
        AND id != :field_id
        ");

        $result = $this->di['db']->findOne('FormField', 'form_id = ? and name = ? and id != ?', array($form_id, $field_name, $field_id));
        return ($result) ? true : false;
    }

    public function getForms()
    {
        $sql = ("
        SELECT f.id, f.name, COUNT( p.id ) as product_count, COUNT( co.id ) as order_count
        FROM  `form` f
        LEFT JOIN product p ON (f.id = p.form_id)
        LEFT JOIN client_order co ON (f.id = co.form_id)
        GROUP BY f.id
        ");

        return $this->di['db']->getAll($sql);
    }

    public function dublicateForm($data)
    {

        $fields = $this->getFormFields($data['form_id']);
        $new_form_id = $this->addNewForm(array(
            "name" => $data['name']
        ));

        if (isset($fields) && is_array($fields)) {
            foreach ($fields as $field_data) {
                $field_data['form_id'] = $new_form_id;
                $this->addNewField($field_data);
            }
        }
        $this->di['logger']->info('Copied form with id %s to new form %s with id %s', $data['form_id'], $data['name'], $new_form_id);
        return $new_form_id;
    }

    public function updateFormSettings($data)
    {
        $show_title = isset($data['show_title'])? $data['show_title'] : "1";
        $type = $data['type'];

        $sql = "UPDATE `form`
                SET `name` =  :form_name
                WHERE id = :id";
        $this->di['db']->exec($sql, array(':form_name' => $data['form_name'], ':id' => $data['form_id']));

        $this->di['logger']->info('Updated form %s name to %s', $data['form_id'], $data['form_name']);

        $style = array(
            "type" => $type,
            "show_title" => $show_title
        );

        $sql2 = "UPDATE `form`
                SET `style` =  :type
                WHERE id = :id";
        $this->di['db']->exec($sql2, array(':type' => json_encode($style, JSON_FORCE_OBJECT), ':id' => $data['form_id']));
        $this->di['logger']->info('Updated form %s type to %s', $data['form_id'], $data['type']);
        return true;
    }


}